package com.zhang.user.client;


import com.fasterxml.jackson.databind.ObjectMapper;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;

import com.zhang.thrift.user.dto.UserDTO;

import javax.servlet.http.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**拦截请求，验证登录状态
 * Created by Michael on 2017/10/31.
 */

public abstract class LoginFilter implements Filter {

    Logger logger=LoggerFactory.getLogger(LoginFilter.class);

    //客户端缓存
    private static Cache<String, UserDTO> cache =
            CacheBuilder.newBuilder().maximumSize(10000)
            .expireAfterWrite(3, TimeUnit.MINUTES).build();


    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;

        //获取token
        String token = request.getParameter("token");
        //验证toknen是否为空
        if(StringUtils.isBlank(token)) {
            Cookie[] cookies = request.getCookies();
            if(cookies!=null) {
                for(Cookie c : cookies) {
                    if(c.getName().equals("token")) {
                        token = c.getValue();
                    }
                }
            }
        }

        UserDTO userDTO = null;
        //token不为空
        if(StringUtils.isNotBlank(token)) {
            userDTO = cache.getIfPresent(token); //从客户端guava缓存取
            if(userDTO==null) {  //没有再去远程取
                userDTO = requestUserInfo(token);  //根据token获取用户信息
                if(userDTO!=null) {
                    cache.put(token, userDTO);  //远程取存在客户端缓存
                }
            }
        }

        if(userDTO==null) {  //如果没有通过token湖区到用户信息，跳转到登录页
//            response.sendRedirect("http://www.mooc.com/user/login");  //模板
            response.sendRedirect("http://127.0.0.1:8082/user/login");  //模板
            return;
        }

        //登录后操作
        login(request, response, userDTO);

        filterChain.doFilter(request, response);  //通过
    }

    protected abstract String userEdgeServiceAddr();

    /**
     * 留给登陆者实现
     * @param request
     * @param response
     * @param userDTO
     */
    protected abstract void login(HttpServletRequest request, HttpServletResponse response, UserDTO userDTO);

    /**
     * 根据token获取用户信息
     * @param token
     * @return
     */
    private UserDTO requestUserInfo(String token) {
        //远程请求  根据token获取用户信息 ---resttemplate
//        String url = "http://"+userEdgeServiceAddr()+"/user/authentication";
        String url = "http://"+"127.0.0.1:8082"+"/user/authentication";
        logger.info("url与原本不同，远程请求获取token:{}",url);
        HttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost(url);
        post.addHeader("token", token);
        InputStream inputStream = null;
        try {
            //返回对象
            HttpResponse response = client.execute(post);
            // 返回的状态--异常
            if(response.getStatusLine().getStatusCode()!= HttpStatus.SC_OK) {
                throw new RuntimeException("request user info failed! StatusLine:"+response.getStatusLine());
            }
            // 返回正常
            inputStream = response.getEntity().getContent();
            byte[] temp = new byte[1024];
            StringBuilder sb = new StringBuilder();
            int len = 0;
            while((len = inputStream.read(temp))>0) {
                sb.append(new String(temp,0,len));
            }
            //转换
            UserDTO userDTO = new ObjectMapper().readValue(sb.toString(), UserDTO.class);
            return userDTO;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(inputStream!=null) {
                try{
                    inputStream.close();
                }catch(Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public void destroy() {

    }
}
